前言
在前幾天的文章裡,我們陸續把「賽博紓壓診所」的 HTML 骨架、CSS 變數、日夜模式以及呼吸燈過場動畫都刻出來了。
回想在 Day 02 提過的 SPA(Single Page Application,單頁式應用) 概念,這個專案從頭到尾都只在同一個 index.html 裡面運作。使用者不需要每次切換分頁就重新整理網頁。今天我們就要把這些零散的畫面區塊全部串起來,用純 JavaScript 打造一套乾淨、好擴充的畫面切換狀態機!
核心觀念:用 ClassList 管理畫面狀態
既然是單頁應用,最直覺的做法就是把每個頁面(首頁、過場、測驗、結果)都用<div class="card">包起來,並且預設除了首頁之外,其他區塊都加上 .hidden(display: none;`)藏起來。
當使用者點擊按鈕時,我們不需要透過後端路由跳轉,只需要透過 JavaScript 去動態操作 DOM 的 classList:把當前畫面的 hidden 加上去,同時把下一個畫面的 hidden 拿掉。這樣就能達成零延遲、超滑順的畫面切換體驗!
動手寫 Code(上):樣式設定
首先,我們在網頁的頭部標籤裡寫好基礎樣式,之後把首頁、呼吸燈過場、測驗畫面與結果報告這四大區的 HTML 結構完整搭建起來:
[data-theme="dark"] {
--bg-color: #121212;
--card-bg: #1e1e1e;
--primary-color: #64b5f6;
--text-main: #e0e0e0;
--text-muted: #9e9e9e;
}
body {
font-family: 'Segoe UI', Microsoft JhengHei, sans-serif;
background: var(--bg-color);
color: var(--text-main);
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
transition: background 0.3s, color 0.3s;
}
.container {
width: 100%;
max-width: 600px;
padding: 20px;
}
.card {
background-color: var(--card-bg);
border-radius: var(--border-radius);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
padding: 30px;
text-align: center;
transition: background-color 0.3s;
}
.btn {
background-color: var(--primary-color);
color: white;
border: none;
border-radius: 50px;
padding: 12px 30px;
font-size: 1rem;
cursor: pointer;
width: 100%;
margin-top: 10px;
}
.breathe-circle {
width: 120px;
height: 120px;
background-color: #90caf9;
border-radius: 50%;
margin: 30px auto;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
animation: breatheAnimation 4s infinite ease-in-out;
}
@keyframes breatheAnimation {
0% { transform: scale(1); background-color: #90caf9; }
50% { transform: scale(1.3); background-color: #42a5f5; }
100% { transform: scale(1.0); background-color: #90caf9; }
}
.hidden { display: none; }
</style>
動手寫 Code(下):用原生 JS 串起全站畫面狀態機
在網頁主體中放入四大區塊,並在最下方編寫狀態切換的 JavaScript 函式。我們把從首頁到過場、再到測驗與結果頁面的切換邏輯全部串聯起來:
<div class="container">
<!-- 1. 首頁區塊 -->
<div id="welcome-screen" class="card">
<h1>🧠 賽博紓壓診所與解碼器</h1>
<p>結合廟宇抽籤、能力雷達圖與惡搞處方籤的頂級心靈小工具。</p>
<button class="btn" onclick="goToBreathe()">進入紓壓診所</button>
</div>
<!-- 2. 深呼吸過場區塊(預設隱藏) -->
<div id="breathe-screen" class="card hidden">
<h2>🧘 調整呼吸,放鬆心情</h2>
<div class="breathe-circle" id="breathe-text">吸氣...</div>
<button class="btn" onclick="startQuiz()">準備好了,開始解碼</button>
</div>
<!-- 3. 測驗區塊(預設隱藏) -->
<div id="quiz-screen" class="card hidden">
<h2 id="question-text">心理測驗進行中...</h2>
<button class="btn" onclick="showResult()">看診斷報告</button>
</div>
<!-- 4. 結果報告區塊(預設隱藏) -->
<div id="result-screen" class="card hidden">
<h1>🏥 賽博病歷診斷報告</h1>
<div style="font-size: 2rem; color: var(--primary-color); margin: 20px 0;">88%</div>
<button class="btn" onclick="restartQuiz()">重新掛號測驗</button>
</div>
</div>
<script>
// 從首頁切換至呼吸過場畫面
function goToBreathe() {
document.getElementById('welcome-screen').classList.add('hidden');
document.getElementById('breathe-screen').classList.remove('hidden');
}
// 從過場畫面進入正式測驗
function startQuiz() {
document.getElementById('breathe-screen').classList.add('hidden');
document.getElementById('quiz-screen').classList.remove('hidden');
}
// 從測驗跳轉至結果報告頁面
function showResult() {
document.getElementById('quiz-screen').classList.add('hidden');
document.getElementById('result-screen').classList.remove('hidden');
}
// 重置測驗並返回首頁
function restartQuiz() {
document.getElementById('result-screen').classList.add('hidden');
document.getElementById('welcome-screen').classList.remove('hidden');
}
</script>
開發小想法與設計巧思
在思考這個專題的架構時,我一直在想:「怎麼樣才能讓使用者在操作時覺得很流暢、沒有負擔?」
傳統網頁換頁常常伴隨著畫面閃爍或重新載入的等待感,但透過這種原生 SPA 的寫法,所有的畫面切換都在毫秒內完成。搭配前面幾天做的呼吸燈過場,不僅能給使用者一個緩衝、達到減壓的效果,也讓整個專案的結構變得非常清爽好維護。完全不需要引入複雜的前端框架,用最純粹的 JavaScript 就能達到很棒的互動體驗!
今日結語與明日預告
今日我們透過 JavaScript 的 classList 操作,順利把前幾天做好的零散頁面串成了完整的 SPA 單頁架構,讓整個診所的流程能夠流暢地跑起來。
明天 Day 06:使用者頭像與設定表單的資料狀態綁定,我們要來處理首頁的頭像選擇與 Email 輸入框,把使用者的個人化設定存起來,準備帶入後續的測驗結果中。我們明天見!
用 hidden class 串起四個畫面,對新手來說比一開始就上框架容易理解很多。流程變長後,分散的切換函式可能漏藏某張卡片;你會考慮做一個 showScreen(id),統一保證同一時間只顯示一個畫面,並順便處理焦點嗎?